﻿#region << 版 本 注 释 >>

/*----------------------------------------------------------------
* 类 名 称 ：EventManager
* 类 描 述 ：事件管理器
* 作    者 ：henrychang
* 创建时间 ：2018/12/30 14:46:55
*******************************************************************
* Copyright @ henrychang 2018. All rights reserved.
*******************************************************************
//----------------------------------------------------------------*/

#endregion << 版 本 注 释 >>

using System;
using System.Collections.Generic;
using TouchFish.SingletonClass;

namespace TouchFish.Event
{
    public delegate void EventDelegate<T>(T e) where T : BaseEvent;

    public delegate void EventDelegate(BaseEvent e);

    /// <summary>
    /// 所有事件的基本事件,都需要继承该类
    /// </summary>
    public class BaseEvent
    {
    }

    public interface IEventSystem
    {
        void AddListener<T>(EventDelegate<T> del) where T : BaseEvent;

        void RemoveListener<T>(EventDelegate<T> del) where T : BaseEvent;

        void Raise(BaseEvent e);
    }

    /// <summary>
    /// 管理，发布事件
    ///
    /// @example 订阅
    ///     AddListener<SomethingHappenedEvent>(OnSomethingHappened);
    ///
    /// @example 取消订阅
    ///     RemoveListener<SomethingHappenedEvent>(OnSomethingHappened);
    ///
    /// @example publish an event
    ///     Raise(new SomethingHappenedEvent());
    ///
    /// </summary>
    public class EventSystem : IEventSystem
    {
        /// <summary>
        /// 实际委托，每个唯一事件有一个委托.
        /// 每个委托都有多个调用列表项。
        /// </summary>
        private Dictionary<Type, EventDelegate> delegates = new Dictionary<Type, EventDelegate>();

        /// <summary>
        /// 仅查找，每个侦听器有一个委托查找
        /// </summary>
        private Dictionary<Delegate, EventDelegate> delegateLookup = new Dictionary<Delegate, EventDelegate>();

        /// <summary>
        /// 添加委托
        /// </summary>
        public void AddListener<T>(EventDelegate<T> del) where T : BaseEvent
        {
            //排除重复监听
            if (delegateLookup.ContainsKey(del))
            {
                return;
            }

            // 创建一个非泛型委托来调用泛型委托，这是我们实际调用的委托
            EventDelegate internalDelegate = (e) => del((T)e);
            delegateLookup[del] = internalDelegate;

            EventDelegate tempDel;
            if (delegates.TryGetValue(typeof(T), out tempDel))
            {
                delegates[typeof(T)] = tempDel += internalDelegate;
            }
            else
            {
                delegates[typeof(T)] = internalDelegate;
            }
        }

        /// <summary>
        /// 移除委托
        /// </summary>
        public void RemoveListener<T>(EventDelegate<T> del) where T : BaseEvent
        {
            EventDelegate internalDelegate;
            if (delegateLookup.TryGetValue(del, out internalDelegate))
            {
                EventDelegate tempDel;
                if (delegates.TryGetValue(typeof(T), out tempDel))
                {
                    tempDel -= internalDelegate;
                    if (tempDel == null)
                    {
                        delegates.Remove(typeof(T));
                    }
                    else
                    {
                        delegates[typeof(T)] = tempDel;
                    }
                }

                delegateLookup.Remove(del);
            }
        }

        /// <summary>
        /// 监听事件的数量.
        /// 对于每个惟一的AddListener，委托查找将增加一个.
        /// 这对调试很有用，其他用处不大.
        /// </summary>
        public int DelegateLookupCount { get { return delegateLookup.Count; } }

        /// <summary>
        /// 将事件广播给所有监听此事件的对象
        /// </summary>
        public void Raise(BaseEvent e)
        {
            EventDelegate del;
            if (delegates.TryGetValue(e.GetType(), out del))
            {
                del.Invoke(e);
            }
        }
    }

    public class EventDispatcher : Singleton<EventDispatcher>, ISingleton
    {
        /// <summary>
        /// common event manager
        /// </summary>
        private EventSystem _commonEventSystem = new EventSystem();

        public void OnSingletonInit()
        {
            _commonEventSystem = new EventSystem();
        }

        public EventSystem CommonEventManager
        {
            get { return this._commonEventSystem; }
            private set { }
        }
    }
}